package com.sparrow.socket.http.handler;

import com.sparrow.common.util.JsonUtil;
import com.sparrow.socket.http.anno.HttpParam;
import com.sparrow.socket.http.bean.HttpMethodWrapper;
import com.sparrow.socket.http.manager.HttpPacketManager;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.*;
import io.netty.util.CharsetUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.net.URI;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

/**
 * Http handler
 */
@ChannelHandler.Sharable
public class HttpPacketHandler extends SimpleChannelInboundHandler<FullHttpRequest> {

    private static Logger logger = LoggerFactory.getLogger(HttpPacketHandler.class);

    @Autowired
    HttpPacketManager httpPacketManager;

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) throws Exception {
        URI uri = new URI(request.uri());
        // 过滤掉对 /favicon.ico 的请求
        // 浏览器通常会自动请求网站根目录下的 favicon.ico 文件 favicon.ico 是显示在浏览器标签页或地址栏中的网站图标，用于提升用户体验和品牌识别度。
        if ("/favicon.ico".equals(uri.getPath())) {
//            logger.info("请求了 /favicon.ico，不做响应");
            return;
        }

        HttpMethod method = request.method();
        Map<String, Object> paramMap = new HashMap<>();
        //处理get方法
        if (HttpMethod.GET.equals(method)) {
            parseQueryParams(request.uri(), paramMap);
        }
        //处理post方法
        else if (HttpMethod.POST.equals(method)) {
            String contentType = request.headers().get(HttpHeaderNames.CONTENT_TYPE);
            if (contentType != null) {
                if (contentType.contains("application/json")) {
                    String json = request.content().toString(CharsetUtil.UTF_8);
                    try {
                        paramMap = JsonUtil.parseMap(json, String.class, Object.class);
                    } catch (Exception e) {
                        sendNotFound(ctx);
                        return;
                    }
                } else if (contentType.contains("application/x-www-form-urlencoded")) {
                    String body = request.content().toString(CharsetUtil.UTF_8);
                    // 在 URLDecoder 中要求传入 URI 格式的字符串，所以这里在前面添加 "?"
                    parseQueryParams("?" + body, paramMap);
                }
            }
        } else {
            sendNotFound(ctx);
            throw new RuntimeException("不支持的操作类型：" + method);
        }
        if (!paramMap.containsKey("packetId")) {
            sendNotFound(ctx);
            return;
        }
        Object packetIdObj = paramMap.get("packetId");
        if (!(packetIdObj instanceof String)) {
            sendNotFound(ctx);
            return;
        }
        // 这里可以继续处理 paramMap 参数
        String packetIdStr = (String) packetIdObj;
        int packetId = Integer.parseInt(packetIdStr);
        HttpMethodWrapper httpMethodWrapper = httpPacketManager.getHttpMethodWrapper(packetId);
        try {
            Object invoke = invokeWithParams(httpMethodWrapper.getBean(), httpMethodWrapper.getMethod(), paramMap);
            if (invoke instanceof CompletableFuture) {
                CompletableFuture future = (CompletableFuture) invoke;
                future.whenComplete((result, throwable) -> {
                    if (throwable != null) {
                        sendNotFound(ctx);
                    } else {
                        response(ctx, result);
                    }
                });
            } else {
                response(ctx, invoke);
            }
        } catch (Throwable t) {
            logger.error("err", t);
            sendNotFound(ctx);
        }
    }

    private static void response(ChannelHandlerContext ctx, Object resp) {
        ByteBuf content = Unpooled.copiedBuffer(JsonUtil.toJSON(resp), CharsetUtil.UTF_8);
        FullHttpResponse fullHttpResponse = new DefaultFullHttpResponse(
                HttpVersion.HTTP_1_1,
                HttpResponseStatus.OK,
                content
        );
        fullHttpResponse.headers().set(HttpHeaderNames.CONTENT_TYPE, "application/json; charset=UTF-8");
        fullHttpResponse.headers().set(HttpHeaderNames.CONTENT_LENGTH, content.readableBytes());
        ctx.writeAndFlush(fullHttpResponse).addListener(ChannelFutureListener.CLOSE);
    }

    public static Object invokeWithParams(Object target, Method method, Map<String, Object> paramMap) throws Exception {
        Parameter[] parameters = method.getParameters();
        Object[] args = new Object[parameters.length];

        for (int i = 0; i < parameters.length; i++) {
            Parameter parameter = parameters[i];
            // 只处理带有 @HttpParam 注解的参数
            if (parameter.isAnnotationPresent(HttpParam.class)) {
                HttpParam anno = parameter.getAnnotation(HttpParam.class);
                String name = anno.name();
                Object value = paramMap.get(name);
                Class<?> type = anno.type();
                if (type == null) {
                    type = parameter.getType();
                }
                args[i] = convertValue(value, type);
            }
        }
        Object invoke = method.invoke(target, args);
        return invoke;
    }

    private static Object convertValue(Object obj, Class<?> targetType) {
        if (obj == null) {
            return null;
        }
        if (obj instanceof String) {
            String value = (String) obj;
            if (targetType == String.class) {
                return value;
            } else if ((targetType == Integer.class || targetType == int.class) && value != null) {
                return Integer.valueOf(value);
            } else if ((targetType == Long.class || targetType == long.class) && value != null) {
                return Long.valueOf(value);
            } else if ((targetType == Boolean.class || targetType == boolean.class) && value != null) {
                return Boolean.valueOf(value);
            } else {
                return JsonUtil.parse(value, targetType);
            }
        } else if (obj instanceof Map) {
            Map<String, Object> map = (Map) obj;
            return JsonUtil.getObjectMapper().convertValue(map, targetType);
        }
        throw new UnsupportedOperationException("不支持的类型 obj:" + obj + " targetType:" + targetType);
    }

    private static void sendNotFound(ChannelHandlerContext ctx) {
        FullHttpResponse response = new DefaultFullHttpResponse(
                HttpVersion.HTTP_1_1,
                HttpResponseStatus.NOT_FOUND,
                Unpooled.copiedBuffer("Not Found", CharsetUtil.UTF_8)
        );
        response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain; charset=UTF-8");
        ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
    }

    private void parseQueryParams(String uri, Map<String, Object> paramMap) {
        QueryStringDecoder decoder = new QueryStringDecoder(uri);
        decoder.parameters().forEach((key, values) -> {
            if (values != null && !values.isEmpty()) {
                paramMap.put(key, values.get(0));
            }
        });
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        logger.error("exceptionCaught ", cause);
        ctx.close();
    }
}
